<?php

namespace App\Models\Auth;

use App\Models\Merchant\Merchant;
use App\Models\Merchant\MerchantUser;
use App\Models\ParkingLot\ParkingLot;
use App\Traits\UuidTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Collection;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use HasApiTokens, HasFactory, Notifiable, UuidTrait, HasRoles;

    const IDENTITY_PARKING_LOT = 'PARKING_LOT';
    const IDENTITY_STATION = 'STATION';
    const IDENTITY_MERCHANT = 'MERCHANT';
    const IDENTITY_SYSTEM = 'SYSTEM';
    const IDENTITY_AGENT = 'AGENT';

    const IDENTITIES = [
        self::IDENTITY_SYSTEM => '系统',
        self::IDENTITY_PARKING_LOT => '车场',
        self::IDENTITY_MERCHANT => '商户',
        self::IDENTITY_STATION => '岗亭',
        self::IDENTITY_AGENT => '运营商',
    ];

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password'
    ];

    protected $attributes = [
        'identity' => ''
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [];

    protected $appends = ['as_identity'];

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    public function getJWTCustomClaims(): array
    {
        return [];
    }

    public function getChildIdsAttribute(): array
    {
        if ($this->isSystemSuper) {
            $useIDs = User::pluck('id');
        } else {
            $useIDs = UserRelation::where('user_id', $this->id)->pluck('child_id');
        }

        return $useIDs->toArray();
    }

    public function parkingLots(): HasManyThrough
    {
        return $this->hasManyThrough(ParkingLot::class, UserParkingLot::class, 'user_id', 'id', 'id', 'parking_lot_id')
            ->select(['id', 'name', 'contact_name', 'phone', 'address']);
    }

    public function getParkingLotIdsAttribute(): array
    {
        if ($this->isSystemSuper) {
            $parkingLotIDs = ParkingLot::pluck('id');
        } else {
            $parkingLotIDs = UserParkingLot::where('user_id', $this->id)->pluck('parking_lot_id');
        }

        return $parkingLotIDs->toArray();
    }

    public function getParkingLotIdAttribute()
    {
        if ($this->identity !== self::IDENTITY_SYSTEM) {
            $parkingLotIDs = UserParkingLot::where('user_id', $this->id)->pluck('parking_lot_id');
            if ($parkingLotIDs->count() === 1) {
                return $parkingLotIDs->first();
            }
        }
        return '';
    }

    public function getLstLoginIpAttribute($value)
    {
        if ($value) {
            $value = ip2long($value);
        } else {
            $value = '';
        }
        return $value;
    }

    public function getIsSystemSuperAttribute(): bool
    {
        return $this->super && ($this->identity === self::IDENTITY_SYSTEM);
    }

    public function getAdminPermissionsAttribute(): array
    {
        $allPermissions = $this->permissionObjs;
        return $allPermissions->pluck('name', 'id')->toArray();
    }

    public function reassignPermissions(): self
    {
        $allPermissions = $this->permissionObjs;
        $this->attributes['permissions'] = $allPermissions;
        $permissionNames = array_values($allPermissions->pluck('name')->toArray());
        if (in_array('system.parking_lot', $permissionNames) && !in_array('parking-lot.manage', $permissionNames)) {
            $permissionNames[] = 'parking-lot.manage';
        }
        $this->attributes['_permissions'] = $permissionNames;
        return $this;
    }

    public function getPermissionObjsAttribute(): Collection
    {
        if (!$this->super) {
            return $this->getAllPermissions();
        }

        $permissionObjs = collect();

        switch ($this->identity) {
            case self::IDENTITY_SYSTEM:
                $permissionObjs = Permission::where('guard_name', 'admin')->orderBy('id')->get();
                break;
            case self::IDENTITY_AGENT: // 车场所有权限+用户管理
                $permissionObjs = Permission::where('guard_name', 'admin')->where('identity', '<>', self::IDENTITY_SYSTEM)->where('identity', '<>', self::IDENTITY_MERCHANT)->orderBy('id')->get()
                    ->merge(Permission::where('name', 'like', 'system.parking_lot%')->get())
                    ->merge(Permission::where('name', 'like', 'system.permission%')->get());
                break;
            case self::IDENTITY_STATION:
                $permissionObjs = Permission::where('guard_name', 'admin')->whereIdentity(self::IDENTITY_STATION)->get();
                break;
            case self::IDENTITY_PARKING_LOT: // 车场列表+用户管理+系统日志
                $permissionObjs = Permission::where('guard_name', 'admin')->where('identity', '<>', self::IDENTITY_SYSTEM)->where('identity', '<>', self::IDENTITY_MERCHANT)->orderBy('id')->get()
                    ->merge(Permission::findMany(['999c9c29-6362-4f3c-8a39-e086e8358ca5', '999ca3ec-29c2-431d-8977-2fa8e09b1fd0', '9c5e3f0f-c03f-4785-8714-68389d689cba']))
                    ->merge(Permission::where('name', 'like', 'system.permission%')->get());
                break;
            case self::IDENTITY_MERCHANT: // 商户节点+用户管理
                $permissionObjs = Permission::where('guard_name', 'admin')->whereIdentity(self::IDENTITY_MERCHANT)->orderBy('id')->get()
                    ->merge(Permission::where('name', 'like', 'system.permission%')->get());
                break;
        }

        return $permissionObjs;
    }

    public function merchant(): HasOneThrough
    {
        return $this->hasOneThrough(Merchant::class, MerchantUser::class, 'user_id', 'id', 'id', 'merchant_id')->select(['id', 'name', 'balance', 'able']);
    }

    public function getAsIdentityAttribute($value)
    {
        if ($this->identity) {
            return \Arr::get(self::IDENTITIES, $this->identity, '');
        }

        return '';
    }
}
